package albert3d.gui;

public class Matrix {
	
	public float projection[] = new float[16];
	public float view[] = new float[16];
	public float normal[] = new float[9];

	public Matrix() {
		
	}
	
	public void perspective(float fovY, float aspect, float near, float far) {

		float angle = (float) Math.toRadians(fovY / 2.0f * (float) Math.PI / 180.0f);
		float c = (float) Math.cos(angle) / (float) Math.sin(angle);
		
		float m[] = new float[16];
		
		m[0] = c / aspect;
		m[1] = 0.0f;
		m[2] = 0.0f;
		m[3] = 0.0f;
		m[4] = 0.0f;
		m[5] = c;
		m[6] = 0.0f;
		m[7] = 0.0f;
		m[8] = 0.0f;
		m[9] = 0.0f;
		m[10] = -(far + near) / (far - near);
		m[11] = -2.0f * (far * near) / (far - near);
		m[12] = 0.0f;
		m[13] = 0.0f;
		m[14] = -1.0f;
		m[15] = 0.0f;
		
		float res[] = new float[16];
		res[0] = projection[0]*m[0] + projection[4]*m[1] + projection[8]*m[2] + projection[12]*m[3];
		res[1] = projection[1]*m[0] + projection[5]*m[1] + projection[9]*m[2] + projection[13]*m[3];
		res[2] = projection[2]*m[0] + projection[6]*m[1] + projection[10]*m[2] + projection[14]*m[3];
		res[3] = projection[3]*m[0] + projection[7]*m[1] + projection[11]*m[2] + projection[15]*m[3];
		res[4] = projection[0]*m[4] + projection[4]*m[5] + projection[8]*m[6] + projection[12]*m[7];
		res[5] = projection[1]*m[4] + projection[5]*m[5] + projection[9]*m[6] + projection[13]*m[7];
		res[6] = projection[2]*m[4] + projection[6]*m[5] + projection[10]*m[6] + projection[14]*m[7];
		res[7] = projection[3]*m[4] + projection[7]*m[5] + projection[11]*m[6] + projection[15]*m[7];
		res[8] = projection[0]*m[8] + projection[4]*m[9] + projection[8]*m[10] + projection[12]*m[11];
		res[9] = projection[1]*m[8] + projection[5]*m[9] + projection[9]*m[10] + projection[13]*m[11];
		res[10] = projection[2]*m[8] + projection[6]*m[9] + projection[10]*m[10] + projection[14]*m[11];
		res[11] = projection[3]*m[8] + projection[7]*m[9] + projection[11]*m[10] + projection[15]*m[11];
		res[12] = projection[0]*m[12] + projection[4]*m[13] + projection[8]*m[14] + projection[12]*m[15];
		res[13] = projection[1]*m[12] + projection[5]*m[13] + projection[9]*m[14] + projection[13]*m[15];
		res[14] = projection[2]*m[12] + projection[6]*m[13] + projection[10]*m[14] + projection[14]*m[15];
		res[15] = projection[3]*m[12] + projection[7]*m[13] + projection[11]*m[14] + projection[15]*m[15];
		
		projection = res.clone();
	}
	
	public void frustum( float left, float right, float bottom, float top, float near, float far) {
		
		float m[] = new float[16];
		
		m[0] = 2.0f * near / (right - left);
		m[1] = 0.0f;
		m[2] = 0.0f;
		m[3] = 0.0f;
		m[4] = 0.0f;
		m[5] = 2.0f * near / (top - bottom);
		m[6] = 0.0f;
		m[7] = 0.0f;
		m[8] = 0.0f;
		m[9] = 0.0f;
		m[10] = -(far + near) / (far - near);
		m[11] = -1.0f;
		m[12] = 0.0f;
		m[13] = 0.0f;
		m[14] = -2.0f * far * near / (far - near);
		m[15] = 0.0f;
		
		float res[] = new float[16];
		res[0] = projection[0]*m[0] + projection[4]*m[1] + projection[8]*m[2] + projection[12]*m[3];
		res[1] = projection[1]*m[0] + projection[5]*m[1] + projection[9]*m[2] + projection[13]*m[3];
		res[2] = projection[2]*m[0] + projection[6]*m[1] + projection[10]*m[2] + projection[14]*m[3];
		res[3] = projection[3]*m[0] + projection[7]*m[1] + projection[11]*m[2] + projection[15]*m[3];
		res[4] = projection[0]*m[4] + projection[4]*m[5] + projection[8]*m[6] + projection[12]*m[7];
		res[5] = projection[1]*m[4] + projection[5]*m[5] + projection[9]*m[6] + projection[13]*m[7];
		res[6] = projection[2]*m[4] + projection[6]*m[5] + projection[10]*m[6] + projection[14]*m[7];
		res[7] = projection[3]*m[4] + projection[7]*m[5] + projection[11]*m[6] + projection[15]*m[7];
		res[8] = projection[0]*m[8] + projection[4]*m[9] + projection[8]*m[10] + projection[12]*m[11];
		res[9] = projection[1]*m[8] + projection[5]*m[9] + projection[9]*m[10] + projection[13]*m[11];
		res[10] = projection[2]*m[8] + projection[6]*m[9] + projection[10]*m[10] + projection[14]*m[11];
		res[11] = projection[3]*m[8] + projection[7]*m[9] + projection[11]*m[10] + projection[15]*m[11];
		res[12] = projection[0]*m[12] + projection[4]*m[13] + projection[8]*m[14] + projection[12]*m[15];
		res[13] = projection[1]*m[12] + projection[5]*m[13] + projection[9]*m[14] + projection[13]*m[15];
		res[14] = projection[2]*m[12] + projection[6]*m[13] + projection[10]*m[14] + projection[14]*m[15];
		res[15] = projection[3]*m[12] + projection[7]*m[13] + projection[11]*m[14] + projection[15]*m[15];
		
		projection = res.clone();
	}
	
	public void loadProjectionIdentity() {
		
		projection[0] = 1.0f;
		projection[1] = 0.0f;
		projection[2] = 0.0f;
		projection[3] = 0.0f;
		projection[4] = 0.0f;
		projection[5] = 1.0f;
		projection[6] = 0.0f;
		projection[7] = 0.0f;
		projection[8] = 0.0f;
		projection[9] = 0.0f;
		projection[10] = 1.0f;
		projection[11] = 0.0f;
		projection[12] = 0.0f;
		projection[13] = 0.0f;
		projection[14] = 0.0f;
		projection[15] = 1.0f;
	}
	
	public void loadViewIdentity() {
		
		view[0] = 1.0f;
		view[1] = 0.0f;
		view[2] = 0.0f;
		view[3] = 0.0f;
		view[4] = 0.0f;
		view[5] = 1.0f;
		view[6] = 0.0f;
		view[7] = 0.0f;
		view[8] = 0.0f;
		view[9] = 0.0f;
		view[10] = 1.0f;
		view[11] = 0.0f;
		view[12] = 0.0f;
		view[13] = 0.0f;
		view[14] = 0.0f;
		view[15] = 1.0f;
	}
	
	public void loadNormalMatrix() {
		normal[0] = 1;
		normal[1] = 0;
		normal[2] = 0;
		normal[3] = 0;
		normal[4] = 1;
		normal[5] = 0;
		normal[6] = 0;
		normal[7] = 0;
		normal[8] = 1;
	}
	
	public void translatef(float x, float y, float z) {
		
		float m[] = new float[16];
		m[0] = 1.0f;
		m[1] = 0.0f;
		m[2] = 0.0f;
		m[3] = 0.0f;
		m[4] = 0.0f;
		m[5] = 1.0f;
		m[6] = 0.0f;
		m[7] = 0.0f;
		m[8] = 0.0f;
		m[9] = 0.0f;
		m[10] = 1.0f;
		m[11] = 0.0f;
		m[12] = x;
		m[13] = y;
		m[14] = z;
		m[15] = 1.0f;
		
		float res[] = new float[16];
		res[0] = view[0]*m[0] + view[4]*m[1] + view[8]*m[2] + view[12]*m[3];
		res[1] = view[1]*m[0] + view[5]*m[1] + view[9]*m[2] + view[13]*m[3];
		res[2] = view[2]*m[0] + view[6]*m[1] + view[10]*m[2] + view[14]*m[3];
		res[3] = view[3]*m[0] + view[7]*m[1] + view[11]*m[2] + view[15]*m[3];
		res[4] = view[0]*m[4] + view[4]*m[5] + view[8]*m[6] + view[12]*m[7];
		res[5] = view[1]*m[4] + view[5]*m[5] + view[9]*m[6] + view[13]*m[7];
		res[6] = view[2]*m[4] + view[6]*m[5] + view[10]*m[6] + view[14]*m[7];
		res[7] = view[3]*m[4] + view[7]*m[5] + view[11]*m[6] + view[15]*m[7];
		res[8] = view[0]*m[8] + view[4]*m[9] + view[8]*m[10] + view[12]*m[11];
		res[9] = view[1]*m[8] + view[5]*m[9] + view[9]*m[10] + view[13]*m[11];
		res[10] = view[2]*m[8] + view[6]*m[9] + view[10]*m[10] + view[14]*m[11];
		res[11] = view[3]*m[8] + view[7]*m[9] + view[11]*m[10] + view[15]*m[11];
		res[12] = view[0]*m[12] + view[4]*m[13] + view[8]*m[14] + view[12]*m[15];
		res[13] = view[1]*m[12] + view[5]*m[13] + view[9]*m[14] + view[13]*m[15];
		res[14] = view[2]*m[12] + view[6]*m[13] + view[10]*m[14] + view[14]*m[15];
		res[15] = view[3]*m[12] + view[7]*m[13] + view[11]*m[14] + view[15]*m[15];
		
		view = res.clone();
	}
	
	public void rotatef(float angle, float x, float y, float z) {
		
		float d = (float) Math.sqrt(x*x + y*y + z*z);
		
		if(d!=1.0f && d!=0.0f) {
			x /= d;
			y /= d;
			z /= d;
		}
		
		float s = (float) Math.sin( angle * (float) Math.PI / 180.0f );
		float c = (float) Math.cos( angle * (float) Math.PI / 180.0f );
		
		float m[] = new float[16];
		m[0] = ( x*x * (1-c) + c );
		m[1] = ( x*y * (1-c) - z*s );
		m[2] = ( x*z * (1-c) + y*s );
		m[3] = 0.0f;
		m[4] = ( y*x * (1-c) + z*s );
		m[5] = ( y*y * (1-c) + c );
		m[6] = ( y*z * (1-c) - x*s );
		m[7] = 0.0f;
		m[8] = ( x*z * (1-c) - y*s );
		m[9] = ( y*z * (1-c) + x*s );
		m[10] = ( z*z * (1-c) + c );
		m[11] = 0.0f;
		m[12] = 0.0f;
		m[13] = 0.0f;
		m[14] = 0.0f;
		m[15] = 1.0f;
		
		float res[] = new float[16];
		res[0] = view[0]*m[0] + view[4]*m[1] + view[8]*m[2] + view[12]*m[3];
		res[1] = view[1]*m[0] + view[5]*m[1] + view[9]*m[2] + view[13]*m[3];
		res[2] = view[2]*m[0] + view[6]*m[1] + view[10]*m[2] + view[14]*m[3];
		res[3] = view[3]*m[0] + view[7]*m[1] + view[11]*m[2] + view[15]*m[3];
		res[4] = view[0]*m[4] + view[4]*m[5] + view[8]*m[6] + view[12]*m[7];
		res[5] = view[1]*m[4] + view[5]*m[5] + view[9]*m[6] + view[13]*m[7];
		res[6] = view[2]*m[4] + view[6]*m[5] + view[10]*m[6] + view[14]*m[7];
		res[7] = view[3]*m[4] + view[7]*m[5] + view[11]*m[6] + view[15]*m[7];
		res[8] = view[0]*m[8] + view[4]*m[9] + view[8]*m[10] + view[12]*m[11];
		res[9] = view[1]*m[8] + view[5]*m[9] + view[9]*m[10] + view[13]*m[11];
		res[10] = view[2]*m[8] + view[6]*m[9] + view[10]*m[10] + view[14]*m[11];
		res[11] = view[3]*m[8] + view[7]*m[9] + view[11]*m[10] + view[15]*m[11];
		res[12] = view[0]*m[12] + view[4]*m[13] + view[8]*m[14] + view[12]*m[15];
		res[13] = view[1]*m[12] + view[5]*m[13] + view[9]*m[14] + view[13]*m[15];
		res[14] = view[2]*m[12] + view[6]*m[13] + view[10]*m[14] + view[14]*m[15];
		res[15] = view[3]*m[12] + view[7]*m[13] + view[11]*m[14] + view[15]*m[15];
		
		view = res.clone();
	}
	
	public void scalef(float x, float y, float z) {
		
		float m[] = new float[16];
		m[0] = x;
		m[1] = 0.0f;
		m[2] = 0.0f;
		m[3] = 0.0f;
		m[4] = 0.0f;
		m[5] = y;
		m[6] = 0.0f;
		m[7] = 0.0f;
		m[8] = 0.0f;
		m[9] = 0.0f;
		m[10] = z;
		m[11] = 0.0f;
		m[12] = 0.0f;
		m[13] = 0.0f;
		m[14] = 0.0f;
		m[15] = 1.0f;
		
		float res[] = new float[16];
		res[0] = view[0]*m[0] + view[4]*m[1] + view[8]*m[2] + view[12]*m[3];
		res[1] = view[1]*m[0] + view[5]*m[1] + view[9]*m[2] + view[13]*m[3];
		res[2] = view[2]*m[0] + view[6]*m[1] + view[10]*m[2] + view[14]*m[3];
		res[3] = view[3]*m[0] + view[7]*m[1] + view[11]*m[2] + view[15]*m[3];
		res[4] = view[0]*m[4] + view[4]*m[5] + view[8]*m[6] + view[12]*m[7];
		res[5] = view[1]*m[4] + view[5]*m[5] + view[9]*m[6] + view[13]*m[7];
		res[6] = view[2]*m[4] + view[6]*m[5] + view[10]*m[6] + view[14]*m[7];
		res[7] = view[3]*m[4] + view[7]*m[5] + view[11]*m[6] + view[15]*m[7];
		res[8] = view[0]*m[8] + view[4]*m[9] + view[8]*m[10] + view[12]*m[11];
		res[9] = view[1]*m[8] + view[5]*m[9] + view[9]*m[10] + view[13]*m[11];
		res[10] = view[2]*m[8] + view[6]*m[9] + view[10]*m[10] + view[14]*m[11];
		res[11] = view[3]*m[8] + view[7]*m[9] + view[11]*m[10] + view[15]*m[11];
		res[12] = view[0]*m[12] + view[4]*m[13] + view[8]*m[14] + view[12]*m[15];
		res[13] = view[1]*m[12] + view[5]*m[13] + view[9]*m[14] + view[13]*m[15];
		res[14] = view[2]*m[12] + view[6]*m[13] + view[10]*m[14] + view[14]*m[15];
		res[15] = view[3]*m[12] + view[7]*m[13] + view[11]*m[14] + view[15]*m[15];
		
		view = res.clone();
	}
	
}